<?php
/**
 * vanephp web framework
 * 数据表模型类
 *
 * @author aray <ofree@qq.com>
 * @link http://www.vanephp.com/s
 * @copyright Copyright &copy; 2010 aray
 * @license http://www.vanephp.com/license
 * @package db
 */

if ( ! defined ( 'INVANE' ) )
	exit ( '!' );

/**
 * 数据表模型类
 * @author aray
 *
 */
class vane_db_tableSupport {
	/**
	 * 数据表名称(设置后，完全表名称为 数据表前缀+数据表名称 )
	 * @var string
	 */
	protected $tableName = '';
	/**
	 * 完全表名称
	 * @var string
	 */
	protected $fullTableName = '';
	/**
	 * 主键列名
	 * @var string
	 */
	protected $primaryKey = '';
	
	/**
	 * 一对一关系
	 * <code>
	 * array(
	 * 'mapping1' => array(
	 * 'tableClass' => '映射表的vane类名称'
	 * 'foreignKey' => '映射外键名称，不设置时默认为主键名称',
	 * 'orderBy' => '排序方式',
	 * 'open' => '布尔值，设置默认启用状态',
	 * ),
	 * 'mapping2' => array(
	 * 'tableClass' => '映射表2的vane类名称',
	 * )
	 * )
	 * </code>
	 * @var array
	 */
	protected $hasOne = array ();
	/**
	 * 一对多关系
	 * <code>
	 * array(
	 * 'mapping1' => array(
	 * 'tableClass' => '映射表的vane类名称'
	 * 'foreignKey' => '映射外键名称，不设置时默认为主键名称',
	 * 'orderBy' => '排序方式',
	 * 'start' => '映射记录的开始行',
	 * 'limit' => '映射记录读取的数量',
	 * 'open' => '布尔值，设置默认启用状态',
	 * ),
	 * 'mapping2' => array(
	 * 'tableClass' => '映射表2的vane类名称',
	 * )
	 * )
	 * </code>
	 * @var array
	 */
	protected $hasMany = array ();
	/**
	 * 多对多关系
	 * <code>
	 * array(
	 * 'mapping1' => array(
	 * 'tableClass' => '映射表的vane类名称'
	 * 'foreignKey' => '映射外键名称，不设置时默认为主键名称',
	 * 'orderBy' => '排序方式',
	 * 'start' => '映射记录的开始行',
	 * 'limit' => '映射记录读取的数量',
	 * 'open' => '布尔值，设置默认启用状态',
	 * ),
	 * 'mapping2' => array(
	 * 'tableClass' => '关联表2的vane类名称',
	 * )
	 * )
	 * </code>
	 * @var array
	 */
	protected $manyToMany = array ();
	
	/**
	 * 验证规则
	 * notEmpty	 不允许为空
	 * min       最小值
	 * max       最大值
	 * minlength 最小长度
	 * maxlength 最大长度
	 * number    只能为数字
	 * date      只能为日期
	 * time      只能为时间
	 * range     数值区域范围
	 * ip        IP地址(IPV4)
	 * url       URL(http/https/ftp)
	 * email     Email
	 * username  用户名
	 * qq        QQ号码(1000 - 99999999999)
	 * tel       电话号码
	 */
	protected $rules = array ();
	/**
	 * 验证错误信息
	 */
	protected $errors = array ();
	
	/**
	 * 获取错误信息
	 */
	public function getErrors ( ) {
		return $this->errors;
	}
	
	/**
	 * 获取主键名称
	 * @return string $primaryKey
	 */
	public function getPrimaryKey ( ) {
		return $this->primaryKey;
	}
	
	/**
	 * 设置主键名称
	 * @param string $primaryKey	主键列名
	 */
	public function setPrimaryKey ( $primaryKey ) {
		$this->primaryKey = $primaryKey;
		return $this;
	}
	
	/**
	 * 设置表名
	 * @param string $tableName		数据表名称
	 */
	public function setTableName ( $tableName ) {
		$this->tableName = $tableName;
		return $this;
	}
	
	/**
	 * 获取表名
	 * @return string $tableName
	 */
	public function getTableName ( ) {
		return $this->tableName;
	}
	
	/**
	 * 设置表名
	 * @param string $fullTableName 完全的数据表名称
	 */
	public function setFullTableName ( $fullTableName ) {
		$this->fullTableName = $fullTableName;
		return $this;
	}
	
	/**
	 * 获取数据库SCHEMA
	 */
	public function getDbSchema ( ) {
		return dbo::getDbSchema ( );
	}
	
	/**
	 * 获取完全表名称
	 * @return string
	 */
	public function getFullTableName ( ) {
		if ( ! empty ( $this->fullTableName ) ) {
			return $this->getDbSchema ( ) . $this->fullTableName . $this->getDbSchema ( );
		}
		static $tbPrefix = null;
		if ( $tbPrefix === null ) {
			$dsn = dbo::getDSN ( );
			if ( isset ( $dsn['prefix'] ) )
				$tbPrefix = $dsn['prefix'];
			else
				$tbPrefix = '';
		}
		$this->setFullTableName ( $tbPrefix . dbo::$this->getTableName ( ) );
		return $this->getFullTableName ( );
	}
	
	/**
	 * 查找并返回多行结果
	 * <code>
	 * vane::singleton('table_tb')->findAll('userid,name,pass','userid = 1','created DESC');
	 * vane::singleton('table_tb')->findAll('userid,name,pass','userid = 1','created DESC',0,10);
	 * </code>
	 * @param string $fields		字段
	 * @param string $conditions	WHERE条件
	 * @param string $orderby		排序方式
	 * @param int $start			开始行
	 * @param int $limit            获取数量
	 * @return array
	 */
	public function findAll ( $fields = '*', $conditions = '1', $orderby = null, $start = null, $limit = null ) {
		$rows = dbo::getAll ( $this->getSelectSql ( $fields, $conditions, $orderby, $start, $limit ) );
		
		foreach ( $this->getORMs ( ) as $mapping => $r ) {
			if ( isset ( $r['open'] ) && ($r['open'] == false || $r['open'] == 'false') )
				continue;
			
			$sfields = isset ( $r['fields'] ) ? $r['fields'] : '*';
			$sprimaryKey = isset ( $r['foreignKey'] ) ? $r['foreignKey'] : $this->getPrimaryKey ( );
			$sorderBy = isset ( $r['orderBy'] ) ? $r['orderBy'] : null;
			$slimit = isset ( $r['limit'] ) ? $r['limit'] : null;
			$sstart = isset ( $r['start'] ) ? $r['start'] : null;
			
			$i = 0;
			foreach ( $rows as $k => & $row ) {
				$scondition = sprintf ( '%s = %d', $sprimaryKey, $row[$sprimaryKey] );
				
				if ( $r['ormType'] == 'hasone' ) {
					$row[$mapping] = vane::singleton ( $r['tableClass'] )->find ( $sfields, $scondition, $sorderBy );
				} elseif ( $r['ormType'] == 'hasmany' ) {
					if ( $limit > 0 && $start == null ) {
						$slimit = $sstart;
						$slimit = null;
					}
					$row[$mapping] = vane::singleton ( $r['tableClass'] )->findAll ( $sfields, $scondition, $sorderBy, $sstart, $slimit );
				} elseif ( $r['ormType'] == 'manytomany' ) {
					if ( isset ( $r['joinTableClass'] ) ) {
						$scondition = sprintf ( '%s IN (SELECT %s FROM %s WHERE %s = %d)', vane::singleton ( $r['tableClass'] )->getPrimaryKey ( ), vane::singleton ( $r['tableClass'] )->getPrimaryKey ( ), vane::singleton ( $r['joinTableClass'] )->getFullTableName ( ), $sprimaryKey, $row[$sprimaryKey] );
						$row[$mapping] = vane::singleton ( $r['tableClass'] )->findAll ( $sfields, $scondition, $sorderBy );
					}
				}
				
				$i ++;
			}
		}
		
		return $rows;
	}
	
	/**
	 * 统计符合结果的总行数 
	 * <code>
	 * vane::singleton('table_tb')->findCount('userid > 10');
	 * </code>
	 * @param string $conditions	WHERE条件
	 */
	public function findCount ( $conditions = '1' ) {
		return dbo::getCol ( $this->getSelectSql ( 'COUNT(1)', $conditions ) );
	}
	
	/**
	 * 查找并返回一行结果
	 * <code>
	 * vane::singleton('table_tb')->find('*','userid = 10');
	 * </code>
	 * @param string $fields		字段
	 * @param string $conditions	WHERE条件
	 * @param string $orderby		排序方式
	 * @return array
	 */
	public function find ( $fields = '*', $conditions = '1', $orderby = null ) {
		$rows = $this->findAll ( $fields, $conditions, $orderby, 1 );
		return array_shift ( $rows );
	}
	
	/**
	 * 使用SQL语句查找并返回所有结果
	 * <code>
	 * // 返回的结果是二维数组
	 * vane::singleton('table_tb')->findBySql('SELECT * FROM XXX');
	 * </code>
	 * @param string $sql		SQL语句(返回的结果是二维数组)
	 */
	public function findBySql ( $sql ) {
		return dbo::getAll ( $sql );
	}
	
	/**
	 * 根据主键查找
	 * <code>
	 * // 返回的结果是一维数组
	 * vane::singleton('table_tb')->findByPrimaryKey(1, 'userid');
	 * </code>
	 * @param int $primaryKey	主键值
	 * @param string $fields	选取的字段，默认为所有(*)
	 */
	public function findByPrimaryKey ( $primaryKey, $fields = '*' ) {
		return $this->find ( $fields, sprintf ( '%s = %d', $this->getPrimaryKey ( ), $primaryKey ) );
	}
	
	/**
	 * 创建记录(支持关联数据)
	 * <code>
	 * vane::singleton('table_tb')->create(array(
	 * '字段1' => '值1',
	 * '字段2' => '值2',
	 * ));
	 * //创建关联数据
	 * vane::singleton('table_tb')->create(array(
	 * '字段1' => '值1',
	 * '字段2' => '值2',
	 * '关联名称' => array(
	 * '关联表字段1' => '值100',
	 * '关联表字段2' => '值101',
	 * )
	 * ));
	 * </code>
	 * @param array $row	关联数组
	 * @return int
	 */
	public function create ( $row = array() ) {
		$createRow = $row;
		// 验证
		if ( ! isEmptyArray ( $this->rules ) ) {
			$validator = vane::singleton ( 'vane_helper_validator' );
			foreach ( $row as $k => $v ) {
				if ( ! is_array ( $v ) ) {
					$validator->setValue ( $v );
					if ( isset ( $this->rules[$k] ) ) {
						foreach ( $this->rules as $kk => $vv ) {
							$funs = explode ( '),', $vv );
							foreach ( $funs as $fun ) {
								$result = null;
								
								$fun = trim ( $fun );
								
								$lpos = strpos ( $fun, '(' );
								$args = '';
								if ( $lpos === false ) {
								} else {
									$args = substr ( $fun, $lpos + 1, strrpos ( $fun, ')' ) - $lpos - 1 );
									$fun = substr ( $fun, 0, $lpos );
								}
								
								if ( $fun != '' ) {
									$result = call_user_func_array ( array (
										$validator, $fun 
									), explode ( ',', $args ) );
									if ( $result == false ) {
										$error = call_user_func ( array (
											$validator, 'getError' 
										), $fun );
										$this->errors[$k][] = $error;
									}
								}
							}
						}
					}
				}
			}
		}
		
		if ( ! isEmptyArray ( $this->errors ) ) {
			return 0;
		}
		
		dbo::query ( $this->getInsertSql ( $row ) );
		$lastInsertId = dbo::getLastInsertId ( );
		
		$orms = $this->getORMs ( );
		$created = true;
		foreach ( $orms as $mapping => $r ) {
			if ( ! $created ) {
				return - 1;
			}
			$sprimaryKey = isset ( $r['foreignKey'] ) ? $r['foreignKey'] : $this->getPrimaryKey ( );
			if ( isset ( $r['open'] ) && $r['open'] == 'false' ) {
			
			} else {
				if ( isset ( $createRow[$mapping] ) ) {
					$createRow[$mapping][$sprimaryKey] = $lastInsertId;
					$created = vane::singleton ( $r['tableClass'] )->create ( $createRow[$mapping] ) > 0 ? true : false;
				}
			}
		}
		
		return $lastInsertId;
	}
	
	/**
	 * 创建使用块方式，一次性创建多条记录(不支持关联数据创建)
	 * <code>
	 * vane::singleton('table_tb')->createRowset(array(
	 * array(
	 * '字段1' => '值1',
	 * '字段2' => '值2',
	 * ),
	 * array(
	 * '字段1' => '值1',
	 * '字段2' => '值2',
	 * ),
	 * array(
	 * '字段1' => '值1',
	 * '字段2' => '值2',
	 * )
	 * ));
	 * </code>
	 * @param array $rowset	创建数据(二维数组)
	 */
	public function createRowset ( $rowset ) {
		$sql = 'INSERT INTO %s(%s) %s';
		$fields = '';
		$values = '';
		
		$i = 0;
		
		foreach ( $rowset as $row ) {
			# 过滤数据表中没有定义的字段
			$this->truncateFields ( & $row );
			
			$vStr = '';
			foreach ( $row as $k => $v ) {
				if ( $i == 0 ) {
					$fields .= ($fields === '' ? "{$k}" : ',' . "$k");
				}
				$vStr .= ($vStr === '' ? "'{$v}'" : ',' . "'{$v}'");
			}
			$values .= ($i == 0 ? ' VALUES(' . $vStr . ')' : ', (' . $vStr . ')');
			$i ++;
		}
		
		$sql = sprintf ( $sql, $this->getFullTableName ( ), $fields, $values );
		dbo::query ( $sql );
		return dbo::getAffected ( );
	}
	
	/**
	 * 更新记录(支持关联)
	 * <code>
	 * $row = array(
	 * '字段1' => '值1',
	 * '字段2' => '值2',
	 * '字段3' => '值3',
	 * );
	 * vane::singleton('table_tb')->update($row,'id = 2');
	 * //支持关联更新(内部执行，如果不需要，在使用前请关闭ORM关系）
	 * vane::singleton('table_tb')->update($row,'id=2');
	 * vane::singleton('table_tb')->closeMapping('关联名称')->update($row,'id = 2');
	 * </code>
	 * @param array $row		更新的数据(数组)
	 * @param string $condition 更新的WHERE条件
	 * @return int
	 */
	public function update ( $row = array(), $condition = '0' ) {
		$upateRow = $row;
		
		// 验证
		if ( ! isEmptyArray ( $this->rules ) ) {
			$validator = vane::singleton ( 'vane_helper_validator' );
			foreach ( $row as $k => $v ) {
				if ( ! is_array ( $v ) ) {
					$validator->setValue ( $v );
					if ( isset ( $this->rules[$k] ) ) {
						foreach ( $this->rules as $kk => $vv ) {
							$funs = explode ( '),', $vv );
							foreach ( $funs as $fun ) {
								$result = null;
								
								$fun = trim ( $fun );
								
								$lpos = strpos ( $fun, '(' );
								$args = '';
								if ( $lpos === false ) {
								} else {
									$args = substr ( $fun, $lpos + 1, strrpos ( $fun, ')' ) - $lpos - 1 );
									$fun = substr ( $fun, 0, $lpos );
								}
								
								if ( $fun != '' ) {
									$result = call_user_func_array ( array (
										$validator, $fun 
									), explode ( ',', $args ) );
									if ( $result == false ) {
										$error = call_user_func ( array (
											$validator, 'getError' 
										), $fun );
										$this->errors[$k][] = $error;
									}
								}
							}
						}
					}
				}
			}
		}
		
		if ( ! isEmptyArray ( $this->errors ) ) {
			return 0;
		}
		
		dbo::query ( $this->getUpdateSql ( $row, $condition ) );
		
		$orms = $this->getORMs ( );
		foreach ( $orms as $mapping => $r ) {
			$sprimaryKey = isset ( $r['foreignKey'] ) ? $r['foreignKey'] : $this->getPrimaryKey ( );
			if ( isset ( $r['open'] ) && $r['open'] == 'false' ) {
			
			} else {
				if ( isset ( $upateRow[$mapping] ) ) {
					$update = $upateRow[$mapping];
					$update[$sprimaryKey] = $upateRow[$sprimaryKey];
					vane::singleton ( $r['tableClass'] )->update ( $update, $condition );
				}
			}
		}
		return dbo::getAffected ( );
	}
	
	/**
	 * 自动创建/更新记录(主键关联)
	 * <code>
	 * //如果创建的数据有包含主键字段，则使用update(更新)方式，反之使用创建方式
	 * //如主键为id，则:
	 * array(
	 * 'id' => 1,
	 * '字段1' => '值1',
	 * '字段2' => '值2',
	 * )
	 * vane::singleton('table_tb')->save($row);
	 * //使用更新方式(update)，
	 * vane::singleton('table_tb')->save(array(
	 * '字段1' => '值1',
	 * '字段2' => '值2',
	 * ));
	 * 使用插入方式
	 * </code>
	 * @param array $row		创建数据(数组)
	 * @return int
	 */
	public function save ( $row = array() ) {
		if ( isset ( $row[$this->getPrimaryKey ( )] ) ) {
			return $this->update ( $row, sprintf ( '%s = %s', $this->getPrimaryKey ( ), $row[$this->getPrimaryKey ( )] ) );
		} else {
			return $this->create ( $row );
		}
	}
	
	/**
	 * 删除指定主键的值
	 * @param int $id			主键ID
	 */
	public function remove ( $id ) {
		dbo::query ( $this->getDeleteSql ( sprintf ( '%s = %d', $this->primaryKey, $id ) ) );
		return dbo::getAffected ( );
	}
	
	/**
	 * 删除符合条件的数据
	 * @param string $condition	条件表达式
	 */
	public function removeByCondition ( $condition = '0' ) {
		dbo::query ( $this->getDeleteSql ( $condition ) );
		return dbo::getAffected ( );
	}
	
	/**
	 * 生成select语句
	 * @param string $fields	  	选取字段
	 * @param string $conditions	WHERE条件
	 * @param string $orderby		排序方式
	 * @return string
	 */
	public function getSelectSql ( $fields, $conditions = '0', $orderby = null, $start = null, $limit = null ) {
		if ( $fields == null )
			return '';
		return sprintf ( 'SELECT %s FROM %s WHERE %s %s %s', $this->getFieldsStr ( $fields ), $this->getFullTableName ( ), $conditions, ($orderby === null ? '' : "ORDER BY $orderby"), ($start === null ? '' : ($limit === null ? 'LIMIT ' . $start : 'LIMIT ' . $start . ',' . $limit)) );
	}
	
	/**
	 * 生成insert语句
	 * @param array $row		  	待插入数据
	 * @return string
	 */
	public function getInsertSql ( $row = array() ) {
		$sql = 'INSERT INTO %s(%s) VALUES(%s)';
		$fields = '';
		$values = '';
		
		# 过滤数据表中没有定义的字段
		$this->truncateFields ( & $row );
		
		# 字段全部被过滤
		if ( count ( $row ) == 0 )
			return '';
		
		foreach ( $row as $k => $v ) {
			$v = $this->qStr ( $v );
			$fields .= ($fields === '' ? "{$k}" : ',' . "$k");
			$values .= ($values === '' ? "'{$v}'" : ',' . "'{$v}'");
		}
		return sprintf ( $sql, $this->getFullTableName ( ), $fields, $values );
	}
	
	/**
	 * 生成update语句			
	 * @param array $row		待更新数据
	 * @param string $condition	WHERE条件
	 * @return string
	 */
	public function getUpdateSql ( $row, $condition ) {
		$sql = 'UPDATE %s SET %s WHERE %s';
		$values = '';
		
		# 过滤数据表中没有定义的字段
		$this->truncateFields ( & $row );
		
		# 字段全部被过滤
		if ( count ( $row ) == 0 )
			return '';
		
		foreach ( $row as $k => $v ) {
			$v = $this->qStr ( $v );
			$v = "{$k} = '{$v}'";
			$values .= ($values === '' ? $v : ',' . $v);
		}
		
		return sprintf ( $sql, $this->getFullTableName ( ), $values, $condition );
	}
	
	/**
	 * 生成delete语句
	 * @param string $condition		WHERE条件
	 * @return string
	 */
	public function getDeleteSql ( $condition ) {
		$sql = 'DELETE FROM %s WHERE %s';
		return sprintf ( $sql, $this->getFullTableName ( ), $condition );
	}
	
	/**
	 * 打开指定的数据表映射			
	 * <code>
	 * // 打开logs映射
	 * vane::singleton('table_tb')->openMapping('logs');
	 * </code>
	 * @param string $mapping		映射名称
	 */
	public function openMapping ( $mapping ) {
		$this->setMappingState ( $mapping, 'true' );
		return $this;
	}
	
	/**
	 * 关闭指定的数据表映射
	 * <code>
	 * // 关闭logs映射
	 * vane::singleton('table_tb')->closeMapping('logs');
	 * </code>
	 * @param string $mapping		映射名称
	 */
	public function closeMapping ( $mapping ) {
		$this->setMappingState ( $mapping, 'false' );
		return $this;
	}
	
	/**
	 * 打开所有数据表映射
	 * <code>
	 * vane::singleton('table_tb')->openAllMapping();
	 * </code>
	 */
	public function openAllMapping ( ) {
		$this->setMappingState ( null, 'true', true );
		return $this;
	}
	
	/**
	 * 关闭所有数据表映射
	 * <code>
	 * vane::singleton('table_tb')->closeAllMapping();
	 * </code>
	 */
	public function closeAllMapping ( ) {
		$this->setMappingState ( null, 'false', true );
		return $this;
	}
	
	/**
	 * 返回指定数据表映射的数据表对象
	 * <code>
	 * // 返回的对象是一个vane_db_tableSupport派生类对象
	 * vane::singleton('table_tb')->getMappingTableClass('logs');
	 * // 上面的相当于
	 * vane::singleton('table_logs');
	 * </code>
	 * @param string $mapping		关联名称
	 * @return mixed
	 */
	public function getMappingTableClass ( $mapping ) {
		$tableClassname = '';
		foreach ( $this->getORMs ( ) as $map => $r ) {
			if ( $map == $mapping ) {
				$tableClassname = $r['tableClass'];
			}
		}
		if ( $tableClassname )
			return vane::singleton ( $tableClassname );
		return null;
	}
	
	/**
	 * 截取过滤未定义的数据表字段
	 * @param $row					过滤的数据
	 * @return string
	 */
	protected function truncateFields ( & $row ) {
		static $metas = null , $fields = null;
		$cacheName = 'meta.' . $this->getFullTableName ( );
		
		if ( $metas === null ) {
			$fields = cache::get ( $cacheName );
			if ( $fields == null ) {
				$allInfo = dbo::getTableMeta ( $this->getFullTableName ( ) );
				$fields = array_to_hashmap ( $allInfo, 'Field', 'Type' );
				foreach ( $fields as $k => $v ) {
					$fields[$k] = preg_replace ( '/[^\d]+/', '', $v );
				}
				cache::set ( $cacheName, $fields );
			}
		}
		
		foreach ( $row as $kk => $v ) {
			if ( isset ( $fields[$kk] ) ) {
				foreach ( $fields as $k => $r ) {
					if ( isset ( $fields[$k] ) ) {
						if ( ! is_array ( $r ) ) {
							$l = $fields[$k];
							if ( $l > 0 ) {
								if ( isset ( $row[$k] ) && strlen ( $row[$k] ) > $l ) {
									$row[$k] = _substr ( $row[$k], 0, $l );
								}
							}
						}
					} else {
						unset ( $row[$kk] );
					}
				}
			} else {
				unset ( $row[$kk] );
			}
		}
		
		return $row;
	}
	
	/**
	 * 获取安全的字段名
	 * @param string $fields		字段名
	 * @return string
	 */
	protected function getFieldsStr ( $fields ) {
		return $fields;
	}
	
	/**
	 * 设置映射状态			
	 * <code>
	 * // 设置单个
	 * vane::singleton('table_tb')->setMappingState('logs', true);
	 * // 设置所有
	 * vane::singleton('table_tb')->setMappingState('logs', true, true);
	 * </code>	
	 * @param string $mapping		关联名称
	 * @param string $state			状态[false,true]
	 * @param boolean $all			是否设置为所有
	 */
	private function setMappingState ( $mapping, $state, $all = false ) {
		foreach ( $this->getORMs ( ) as $map => $r ) {
			if ( $all === true ) {
				if ( isset ( $this->hasOne[$map] ) )
					$this->hasOne[$map]['open'] = $state;
				if ( isset ( $this->hasMany[$map] ) )
					$this->hasMany[$map]['open'] = $state;
				if ( isset ( $this->manyToMany[$map] ) )
					$this->manyToMany[$map]['open'] = $state;
				
				continue;
			}
			if ( $mapping == $map ) {
				if ( $r['ormType'] == 'hasone' ) {
					$this->hasOne[$map]['open'] = $state;
				} elseif ( $r['ormType'] == 'hasmany' ) {
					$this->hasMany[$map]['open'] = $state;
				} elseif ( $r['ormType'] == 'manytomany' ) {
					$this->manyToMany[$map]['open'] = $state;
				}
			}
		}
	}
	
	/**
	 * 获取ORM对象关系
	 */
	private function getORMs ( ) {
		$orms = array ();
		foreach ( $this->hasOne as $k => $r ) {
			$r['ormType'] = 'hasone';
			$orms[$k] = $r;
		}
		foreach ( $this->hasMany as $k => $r ) {
			$r['ormType'] = 'hasmany';
			$orms[$k] = $r;
		}
		foreach ( $this->manyToMany as $k => $r ) {
			$r['ormType'] = 'manytomany';
			$orms[$k] = $r;
		}
		return $orms;
	}
	
	/**
	 * 字符串转换
	 * @param string $str
	 * @return string
	 */
	private function qStr ( $str ) {
		return addslashes ( $str );
	}
}